package ldh.serialize.freemaker;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import ldh.serialize.Serialized;
import ldh.serialize.register.Register;
import ldh.serialize.type.EnumSerialized;
import ldh.serialize.type.IterableSerialized;
import ldh.serialize.type.MapSerialized;
import ldh.serialize.util.ClassInfo.ClassData;

public class FreeMakerUtil {

	public static String upFirst(String str) {
		if (str == null || str.trim().equals("")) return str;
		return str.substring(0, 1).toUpperCase() + str.substring(1);
	}
	
	public static String firstLower(String str) {
		if (str == null || str.trim().equals("")) return str;
		return str.substring(0, 1).toLowerCase() + str.substring(1);
	}
	
	public static String lowers(String str) {
		if (str == null || str.trim().equals("")) return str;
		return str.toLowerCase();
	}
	
	public static boolean underLine(String str) {
		if (str == null || str.trim().equals("")) return false;
		int t = str.indexOf("_");
		if (t > -1) {
			return true;
		}
		return false;
	}
	
	public static Set<String> imports(Set<String> importList) {
		Set<String> set = new HashSet<String>();
		for (String str : importList) {
			if (!str.startsWith("java.lang")) {
				set.add(str);
			}
		}
		return set;
	}
	
	public static String javaName(String name) {
		int t = name.indexOf("_");
		String str = name;
		if (t > -1) {
			String prefix = name.substring(0, t);
			String suffix = name.substring(t+1);
			str = prefix + suffix.substring(0, 1).toUpperCase() + suffix.substring(1);
		} 
		t = name.indexOf("_");
		if (t > -1) {
			return javaName(str);
		}
		return name.substring(0,1).toLowerCase() + name.substring(1);
	}
	
	public static String javaName(String table, String frefix) {
		if (frefix == null || frefix.trim().equals("")) {
			String t = table.toLowerCase();
			return javaName(t);
		} else {
			int t = table.toLowerCase().indexOf(frefix.toLowerCase());
			if (t == 0) {
				String ls = table.toLowerCase().substring(t + frefix.length());
				return javaName(ls);
			} else {
				return javaName(table);
			}
		}
	}
	
	public static String beanName(String table) {
		String str = javaName(table.toLowerCase());
		return str.substring(0, 1).toUpperCase() + str.substring(1);
	}
	
	public static String lower(String name) {
		return name.substring(0, 1).toLowerCase() + name.substring(1);
	}
	
	public static String firstUpper(String name) {
		return name.substring(0, 1).toUpperCase() + name.substring(1);
	}
	
	public static String getSerializedName(ClassData classData) {
		Class<?> clazz = classData.getField().getType();
		Serialized<?> serialized = Register.getInstance().getSerialized(clazz);
		if (serialized != null) {
			return "new " + serialized.getClass().getSimpleName() + "()";
		}
		if (clazz.isArray()) {
			clazz = clazz.getComponentType();
			serialized = Register.getInstance().getSerialized(clazz);
			if (serialized == null) {
				throw new RuntimeException("not this class:" + clazz);
			}
			return "new ArraySerialized(new " + serialized.getClass().getSimpleName() + "())";
		} else if (clazz.isEnum()) {
			return "new EnumSerialized(" + clazz.getSimpleName() + ".class)";
		}  else if (Iterable.class.isAssignableFrom(clazz)) {
			Type type = classData.getField().getGenericType();
			if (type instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType)type;
	            Type basicType = parameterizedType.getRawType();   
	            Type[] types = parameterizedType.getActualTypeArguments();   
	            Class<?> key = (Class<?>) types[0];
	            Serialized<?> keySerialized = Register.getInstance().getSerialized(key);
	            return  "new IterableSerialized( new " + keySerialized.getClass().getSimpleName() + "())";
			}
			serialized = Register.getInstance().getSerialized(clazz);
			if (serialized == null) {
				throw new RuntimeException("not this class:" + clazz);
			}
			return "new " + serialized.getClass().getSimpleName() + "()";
		} else if (Map.class.isAssignableFrom(clazz)) {
			Type type = classData.getField().getGenericType();
			if (type instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType)type;
				// ��ȡ��������Ϣ����Map   
	            Type basicType = parameterizedType.getRawType();   
	            System.out.println("������Ϊ��"+basicType);   
	            // ��ȡ�������͵ķ��Ͳ���   
	            Type[] types = parameterizedType.getActualTypeArguments();   
	            Class<?> key = (Class<?>) types[0];
	            Class<?> value = (Class<?>) types[1];
	            Serialized<?> keySerialized = Register.getInstance().getSerialized(key);
	            Serialized<?> valueSerialized = Register.getInstance().getSerialized(value);
	            return "new MapSerialized(new " + keySerialized.getClass().getSimpleName() + "(), new " 
	            		+ valueSerialized.getClass().getSimpleName()+"())";
			}
		}
		
		throw new RuntimeException("not this class:" + clazz);
	}
	
	public static Serialized<?> getSerialized(ClassData classData) {
		Class<?> clazz = classData.getField().getType();
		Serialized<?> serialized = Register.getInstance().getSerialized(clazz);
		if (serialized != null) {
			return serialized;
		}
		if (clazz.isArray()) {
			clazz = clazz.getComponentType();
			serialized = Register.getInstance().getSerialized(clazz);
			if (serialized == null) {
				throw new RuntimeException("not this class:" + clazz);
			}
			return serialized;
		} else if (clazz.isEnum()) {
			return new EnumSerialized(clazz);
		}  else if (Iterable.class.isAssignableFrom(clazz)) {
			Type type = classData.getField().getGenericType();
			if (type instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType)type;
	            Type basicType = parameterizedType.getRawType();   
	            Type[] types = parameterizedType.getActualTypeArguments();   
	            Class<?> key = (Class<?>) types[0];
	            Serialized<?> keySerialized = Register.getInstance().getSerialized(key);
	            return  new IterableSerialized(keySerialized);
			}
			serialized = Register.getInstance().getSerialized(clazz);
			if (serialized == null) {
				throw new RuntimeException("not this class:" + clazz);
			}
			return serialized;
		} else if (Map.class.isAssignableFrom(clazz)) {
			Type type = classData.getField().getGenericType();
			if (type instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType)type;
	            Type basicType = parameterizedType.getRawType();   
	            Type[] types = parameterizedType.getActualTypeArguments();   
	            Class<?> key = (Class<?>) types[0];
	            Class<?> value = (Class<?>) types[1];
	            Serialized<?> keySerialized = Register.getInstance().getSerialized(key);
	            Serialized<?> valueSerialized = Register.getInstance().getSerialized(value);
	            return new MapSerialized(keySerialized, valueSerialized);
			}
		}
		
		throw new RuntimeException("not this class:" + clazz);
	}
	
	private static void check(Serialized<?> serialized, Class<?> clazz) {
		if (serialized == null) {
			throw new RuntimeException("not this class:" + clazz);
		}
	}
	
	public static void main(String[] args) {
		Integer id = 12;
		if (id.getClass().isPrimitive() || (Number.class.isAssignableFrom(id.getClass()))) {
			System.out.println("true");
		} else {
			System.out.println("false");
		}
		
		Map<String, Integer> map = new HashMap<String, Integer>();
		Type type = map.getClass().getGenericSuperclass();
		System.out.println(map.getClass().getComponentType());
		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType)type;
			// ��ȡ��������Ϣ����Map   
            Type basicType = parameterizedType.getRawType();   
            System.out.println("������Ϊ��"+basicType);   
            // ��ȡ�������͵ķ��Ͳ���   
            Type[] types = parameterizedType.getActualTypeArguments();   
            for (int i = 0; i < types.length; i++) {   
                System.out.println("��"+(i+1)+"�����������ǣ�"+types[i].getClass());   
            }  
		}
		System.out.println(Map.class.isAssignableFrom(map.getClass()));
		
		Integer[] its = new Integer[]{12, 323, 34};
		System.out.println(its.getClass().getComponentType());
		System.out.println(String.class);
	}
	
	public static boolean isArray(ClassData classData) {
		Class<?> clazz = classData.getField().getType();
		return clazz.isArray();
	}
	
	public static boolean isIterable(ClassData classData) {
		Class<?> clazz = classData.getField().getType();
		return Iterable.class.isAssignableFrom(clazz);
	}
	
	public static boolean isMap(ClassData classData) {
		Class<?> clazz = classData.getField().getType();
		return Map.class.isAssignableFrom(clazz);
	}
}
